using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace SimianReshaper
{
	public class SupportiveFunctions
	{
		public static RunResults RunExecutable(string executablePath,
			string arguments,
			string workingDirectory)
		{
			RunResults runResults = new RunResults();
			runResults.Output = new List<string>();
			runResults.Error = new List<string>();
			runResults.RunException = null;
			try
			{
				if (File.Exists(executablePath))
				{
					using (Process proc = new Process())
					{
						proc.StartInfo.FileName = executablePath;
						proc.StartInfo.Arguments = arguments;
						proc.StartInfo.WorkingDirectory = workingDirectory;
						proc.StartInfo.UseShellExecute = false;
						proc.StartInfo.CreateNoWindow = true;
						proc.StartInfo.RedirectStandardOutput = true;
						proc.StartInfo.RedirectStandardError = true;
						proc.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e)
						{
							runResults.Output.Add(e.Data);
						};
						proc.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e)
						{
							runResults.Error.Add(e.Data);
						};

						proc.Start();
						proc.BeginOutputReadLine();
						proc.BeginErrorReadLine();
						proc.WaitForExit();
						runResults.ExitCode = proc.ExitCode;
					}
				}
				else
				{
					throw new ArgumentException("Invalid executable path.", "executablePath");
				}
			}

			catch (Exception e)
			{
				runResults.RunException = e;
			}
			return runResults;
		}

		public static StringBuilder ReformatErrors(List<string> outputs,
			Preferences preferences,
			Collection<DuplicationEntity> entityList)
		{
			StringBuilder builder = new StringBuilder();
			int errorCount = outputs.Count;
			for (int index = 0; index < errorCount; index++)
			{
				string outputMessage = outputs[index];
				if (!string.IsNullOrEmpty(outputMessage))
				{
					Regex firstErrorMatchRegex = new Regex("Found [0-9]* duplicate lines in the following files:");
					Match firstErrorMatch = firstErrorMatchRegex.Match(outputMessage);
					if (firstErrorMatch.Success)
					{
						List<string> errorMessages = new List<string>();
						errorMessages.Add(outputMessage);
						DuplicationEntity entity = new DuplicationEntity();
						entity.Header = outputMessage;
						for (int errorIndex = index + 1; errorIndex < errorCount; errorIndex++)
						{
							string internalError = outputs[errorIndex];
							if (!string.IsNullOrEmpty(internalError))
							{
								//reformat actual error
								Regex internalErrorActualErrorRegEx = new Regex(@"Between lines (?<LineNumberOne>[0-9]*) and (?<LineNumberTwo>[0-9]*) in (?<FilePath>.*)");
								Match internalErrorActualErrorMatch = internalErrorActualErrorRegEx.Match(internalError);
								Match internalErrorFirstErrorMatch = firstErrorMatchRegex.Match(internalError);
								if (internalErrorActualErrorMatch.Success)
								{
									string filePath = internalErrorActualErrorMatch.Groups["FilePath"].Value;
									if (ValidEntry(preferences, filePath)) //ignore designer files
									{
										string fromLine = internalErrorActualErrorMatch.Groups["LineNumberOne"].Value;
										string toLine = internalErrorActualErrorMatch.Groups["LineNumberTwo"].Value;
										string modifiedOutput = string.Format("{0}({1}, 0): Duplicated lines between {1}, {2}",
											filePath,
											fromLine,
											toLine);
										if (!preferences.IgnoreList.Contains(modifiedOutput))
										{
											errorMessages.Add(modifiedOutput);
											entity.AppendEntity(new DuplicatedLocation(filePath, int.Parse(fromLine), int.Parse(toLine)));
										}
									}
								}
								else
								{
									index = errorIndex - 1;
									if (errorMessages.Count > 1)
									{
										builder.Append("*************************************************************************************************************************************").Append(Environment.NewLine);
										foreach (string output in errorMessages)
										{
											builder.Append(output).Append(Environment.NewLine);
										}
										entityList.Add(entity);
									}
									break;
								}
							}
						}
					}
					else
					{
						builder.Append(outputMessage).Append(Environment.NewLine);
					}
				}
			}
			return builder;
		}

		private static bool ValidEntry(Preferences preferences, string filePath)
		{
			return (preferences.IgnoreDesignerErrors && !(filePath.Contains(".Designer.cs") || filePath.Contains(".designer.cs"))) 
				|| !preferences.IgnoreDesignerErrors;
		}
	}
}
